package com.ssl.mybatisinterceptor.interceptor;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.ibatis.executor.resultset.DefaultResultSetHandler;
import org.apache.ibatis.executor.resultset.ResultSetHandler;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ResultMap;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.Statement;
import java.util.*;

/**
 * 描述：
 *
 * @author ssl
 * @create 2021/03/10 22:36
 */
@Component
@Intercepts({@Signature(type = ResultSetHandler.class, method = "handleResultSets", args = {Statement.class})})
public class MybatisInterceptor implements Interceptor {
    private static final String AESKEY = "";
    // 需要解密的列名：(key)entity - > (value)columns;
    public static Map<String, List<String>> ENCRYPTED_COLUMN = new HashMap<>();

    static {
        List<String> columns = new ArrayList<>();
        // 实体中需要解密的列名集合
        columns.add("idcard");
        columns.add("salary");
        ENCRYPTED_COLUMN.put("User", columns);
    }

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        List resultList = new ArrayList();
        DefaultResultSetHandler defaultResultSetHandler = (DefaultResultSetHandler) invocation.getTarget();
        MetaObject metaStatementHandler = SystemMetaObject.forObject(defaultResultSetHandler);
        // MappedStatement维护了一条<select|update|delete|insert>节点的封装
        MappedStatement mappedStatement = (MappedStatement) metaStatementHandler.getValue("mappedStatement");
        List<ResultMap> resultMaps = mappedStatement.getResultMaps();
        // 映射的实体类型名称
        Class<?> resultType = resultMaps.get(0).getType();
        // 结果集总数
        int resultMapCount = resultMaps.size();
        if (0 < resultMapCount) {
            Statement statement = (Statement) invocation.getArgs()[0];
            // 结果集
            ResultSet resultSet = statement.getResultSet();
            if (null != resultSet) {
                //获得对应列名
                ResultSetMetaData metaData = resultSet.getMetaData();
                // 列名存放集合
                List<String> columnList = new ArrayList<>();
                for (int i = 1; i <= metaData.getColumnCount(); i++) {
                    columnList.add(metaData.getColumnName(i));
                }
                while (resultSet.next()) {
                    LinkedHashMap<String, Object> resultMap = new LinkedHashMap<>();
                    for (String colName : columnList) {
                        resultMap.put(colName, resultSet.getString(colName));
                    }
                    // 解密

                    decrypt(resultType, resultMap);
                    Object o = resultType.newInstance();
                    //将转换后的map转换为实体类中
                    BeanUtils.populate(o, resultMap);
                    resultList.add(o);
                }
                return resultList;
            }
        }
        return invocation.proceed();
    }

    private void decrypt(Class<?> resultType, LinkedHashMap<String, Object> resultMap) {
        List<String> colums = ENCRYPTED_COLUMN.get(resultType.getSimpleName());
        if (colums.isEmpty()) {
            return;
        }
        StringBuffer columnTypeName = null;
        for (String column : colums) {
            for (Map.Entry<String, Object> entry : resultMap.entrySet()) {
                if (column.equals(entry.getKey())) {
                    // 需要解密的列
                    try {
                        columnTypeName = new StringBuffer(resultType.getDeclaredField(column).getType().getSimpleName
                                ());
                    } catch (NoSuchFieldException e) {
                        e.printStackTrace();
                        return;
                    }
                    entry.setValue(decrypt(columnTypeName.toString(), String.valueOf(entry.getValue())));
                }
            }
        }

    }

    private static Object decrypt(String columnTypeName, String signData) {
        StringBuffer result = new StringBuffer();
        if (signData.startsWith("AES:")) {
            // TODO 解密
            result = new StringBuffer(signData.substring(signData.indexOf("AES:")+4, signData.length()));
        }
        switch (columnTypeName) {
            case "BigDecimal":
                return new BigDecimal(result.toString());
            default:
                return result.toString();
        }

    }
}
